package com.sig.opengl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.sig.formes.*;
import com.sig.utils.Pair;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

public class MyGLRenderer implements GLSurfaceView.Renderer {

	private float[] mMVPMatrix = new float[16];
	private float[] mProjMatrix = new float[16];
	private float[] mVMatrix = new float[16];

	public static float x = 0;
	public static float y = 0;
	public static float z = 30;
	
	public static float ancien_x = 0;
	public static float ancien_y = 0;
	public static float ancien_z = 30;

	public volatile List<IForme> _formes = new ArrayList<IForme>();
	public volatile List<IForme> _formes_chemin = new ArrayList<IForme>();
	
	public volatile HashMap<String,Layer> _layers = new HashMap<String, Layer>();
	public static final String DEFAULT_LAYER = "defaut";
	// option des layers
	public volatile List< Pair<Layer> > _layers_by_priority = 
			new ArrayList< Pair<Layer> >();
	
	public static volatile boolean BORDER_ENABLE = true;

	
	public MyGLRenderer(){
		//creation des different layer

		create_layers();
	}
	private void add_layer(String name, float[] color,boolean enable,boolean canBeDisable, int priority)
	{
		Layer l = new Layer(color,name,new LayerParam(enable,priority));
		l.getParam().setCanBeDisable(canBeDisable);
		this._layers.put(name,l);
		this._layers_by_priority.add(new Pair<Layer>(l.getParam().getPriority(),l));
	}
	

	private void add_layer_with_border(String name, float[] color,
			boolean enable, int priority, boolean border,boolean canBeDisable) {
		add_layer(name, color, enable,canBeDisable, priority);
		Layer l = this._layers.get(name);
		l.border_enable = true;
		
	}
	
	private void create_layers()
	{
		//polygone
		boolean enable_building = true;
		boolean enable_roads= true;
		//batiment 
		add_layer("building",Forme.gris_claire,enable_building,true,20);
		add_layer("university",Forme.gris_claire,enable_building,true,21);
		
		//area
		add_layer("brownfield",Forme.vert_fonce,enable_building,true,12);
		add_layer("construction",Forme.gris_claire,enable_building,true,12);
		add_layer("meadow",Forme.gris_claire,enable_building,true,12);
		add_layer("grass",Forme.vert,enable_building,true,11);
		add_layer("commercial",Forme.gris_claire,enable_building,true,11);
		add_layer("basin",Forme.bleuclair,enable_building,true,13);
		add_layer("cemetery",Forme.gris_claire,enable_building,true,12);
		add_layer("forest",Forme.vert_fonce,enable_building,true,11);
		add_layer("farmland",Forme.gris_claire,enable_building,true,11);
		add_layer("industrial",Forme.gris_claire,enable_building,true,11);
		add_layer("residential",Forme.gris_claire,enable_building,true,11);		
		add_layer("trou",Forme.defaut,enable_building,false,44);
		add_layer(DEFAULT_LAYER, Forme.defaut, enable_building,false, 27);
		
		// Interieur Batiment
		add_layer("salle",Forme.gris_fonce,false,false,40);
		add_layer("couloir",Forme.vert,false,false,35);
		add_layer("dijkstraa",Forme.bleuclair,true,true,43);
		add_layer("mur",Forme.noir,false,false,41);
		add_layer("toilette",Forme.bleu,false,false,40);
		add_layer("porte",Forme.blanc,false,false,42);
		add_layer("lettre",Forme.blanc,false,false,44);
		add_layer("sol",Forme.vert,false,false,40);

		//routes
		add_layer_with_border("chemin", Forme.jaune, enable_roads, 28,
				BORDER_ENABLE,true);
		add_layer_with_border("route", Forme.blanc, enable_roads, 28,
				BORDER_ENABLE,true);
		add_layer_with_border("autre", Forme.jaune, enable_roads, 28,
				BORDER_ENABLE,true);
		
		//localisation 
		add_layer("localisation", Forme.rouge, false, false, 45);
		
		//trie de la liste
		Collections.sort(this._layers_by_priority);
	}
	
	public HashMap<String, Layer> get_layers() {
		return _layers;
	}
	
	public HashMap<String,Layer> get_layers_batiments(){
		HashMap<String,Layer> hash = new HashMap<String, Layer>();
		_layers.get("salle").getParam().setCanBeDisable(true);
		_layers.get("couloir").getParam().setCanBeDisable(true);	
		_layers.get("dijkstraa").getParam().setCanBeDisable(true);
		hash.put("salle",_layers.get("salle"));
		hash.put("couloir",_layers.get("couloir"));
		hash.put("dijkstraa",_layers.get("dijkstraa"));

		return hash;

	}

	public void set_layers(HashMap<String, Layer> _layers) {
		this._layers = _layers;
	}
	
	public void onResume() {

		Matrix.setIdentityM(mMVPMatrix, 0);
		Matrix.setIdentityM(mProjMatrix, 0);
		Matrix.setIdentityM(mVMatrix, 0);

		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
		for(IForme f : _formes){
			f.recreer();
		}

		for(IForme f : _formes_chemin){
			f.recreer();
		}
	}
	/*
	public void ajouterFormes(){
		Forme.ajouterFormes(_formes);
	}*/

	////////////////////////////:Managed formes://////////////////////////
	
	public void ajouterChemin(List<Forme> formes){
		getLayerDijkstraa().getParam().setEnable(true);
		getLayerDijkstraa().getFormes().clear();
		getLayerDijkstraa().add_Forme(formes);
		getLayerDijkstraa().recreer();
	}
	
	public void ajouterFormes(List<IForme> formes) {
		_formes.addAll(formes);
		
		//centrer
		x = Point.minX+(Point.maxX-Point.minX)/2;
		y = Point.minY+(Point.maxY-Point.minY)/2;


	}
	
	/////////////////////////////:OPENGL:////////////////////////////////////

	@Override
	public void onSurfaceCreated(GL10 unused, EGLConfig config) {

		// Set the background frame color
		GLES20.glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
		//if(_formes.isEmpty())
		//	ajouterFormes();
		
		
		Log.e("OPENL", "onSurfaceCreated");
	}

	public Layer getLayerDijkstraa(){
		return this._layers.get("dijkstraa");
	}
	@Override
	public void onDrawFrame(GL10 gl) {
		synchronized(this) {
			//ajouterFormes();
			//if(_formes != null && !_formes.isEmpty()){
				// Draw background color
				GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
				
				// Set the camera position (View matrix)
				Matrix.setLookAtM(mVMatrix, 0, x,    y,    z,    x,       y,       0,       0,   1,   0);
				//  Matrix.setLookAtM(mVMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)

				// Calculate the projection and view transformation
				Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);

					//draw
				/*
					for(IForme forme : _formes){	
						forme.draw(mMVPMatrix);

						// Calculate the projection and view transformation
						Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
					}

					if(_formes_chemin != null && !_formes_chemin.isEmpty()){
						for(IForme forme : _formes_chemin){			
							forme.draw(mMVPMatrix);

							// Calculate the projection and view transformation
							Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
						}
					}
					*/
				for( Pair<Layer> e : this._layers_by_priority)
				{
					Layer l = e.getB();
					LayerParam lp = l.getParam();
					if(lp.enable)
					{
						
						if(l.border_enable && l.Border != null)
						{
							Log.v("sig_layer", " draw layer border "+l.getType());
							l.Border.draw(mMVPMatrix);
						}
						Log.v("sig_layer", " draw layer "+l.getType());
						l.draw(mMVPMatrix);
						Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
					}
				}
			//}
		}

	}

	public static final int dist = 20000;

	@Override
	public void onSurfaceChanged(GL10 unused, int width, int height) {
		// Adjust the viewport based on geometry changes,
		// such as screen rotation
		GLES20.glViewport(0, 0, width, height);

		float ratio = (float) width / height;

		// this projection matrix is applied to object coordinates
		// in the onDrawFrame() method
		Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1,     1,   2,    dist);
		//Matrix.frustumM(m, offset,    left,   right, bottom, top, near, far)

	}

	public static int loadShader(int type, String shaderCode){
		int shader = GLES20.glCreateShader(type);
		// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
		// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)

		// add the source code to the shader and compile it
		GLES20.glShaderSource(shader, shaderCode);
		GLES20.glCompileShader(shader);

		return shader;
	}

	/**
	 * Utility method for debugging OpenGL calls. Provide the name of the call
	 * just after making it:
	 *
	 * <pre>
	 * mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
	 * MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
	 *
	 * If the operation is not successful, the check throws an error.
	 *
	 * @param glOperation - Name of the OpenGL call to check.
	 */
	public static void checkGlError(String glOperation) {
		int error;
		while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
			System.err.println(glOperation + ": glError " + error);
			throw new RuntimeException(glOperation + ": glError " + error);
		}
	}


	private float _previousX;
	private float _previousY;
	private final float TOUCH_SCALE_FACTOR = 180.0f / 320;

	public void rotate(float x, float y, GLSurfaceView surfaceView){

		float dx = x - _previousX;
		float dy = y - _previousY;

		// reverse direction of rotation above the mid-line
		if (y > surfaceView.getHeight() / 2) {
			dx = dx * -1 ;
		}

		// reverse direction of rotation to left of the mid-line
		if (x < surfaceView.getWidth() / 2) {
			dy = dy * -1 ;
		}

		if(_formes != null && _formes.size()>=4){
			_formes.get(0).addAngle( dx+dy * TOUCH_SCALE_FACTOR);
			_formes.get(1).addAngle( dx+dy * TOUCH_SCALE_FACTOR );
			_formes.get(2).addAngle( -(dx+dy * TOUCH_SCALE_FACTOR));
			_formes.get(3).addAngle( dx+dy * TOUCH_SCALE_FACTOR);
			if(_formes.size()>=5)
				_formes.get(4).addAngle( -(dx+dy * TOUCH_SCALE_FACTOR));  
		}


		_previousX = x;
		_previousY = y;

	}
}


